/*
 * @Author: Oscar Pena
 * CS431 2011
 * This class allows the user to create and edit an environment to test the finch on. 
 * The user can create an evironment by building walls and beepers on the grid. 
 * He/she can place the finch at any desired starting position. 
 * Finch and beeperes cannot be placed on top of a wall. There can only be one finch in an environment. 
 * This can be used to build a maze or other complicated environments to test the program.
 * */
package FlowGram.Application.SimulatorWindow.TerrainEditor;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.ParseException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeListener;

import FlowGram.Application.Application;
import FlowGram.Application.SimulatorWindow.Simulator.SimulatorEngineWindow;

public class TerrainEditorWindow extends JPanel  implements ActionListener, ItemListener {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	final static int ADDBEEPER = 0;
	final static int REMOVEBEEPER = 1;
	final static int ADDWALL = 2;
	final static int ADDFINCH = 3;
	private JPanel rightPanel = new JPanel();
	private JPanel centerPanel = new JPanel();
	private JButton beeperButton = new JButton("Add Beeper");
	private JButton removeBeeperButton = new JButton("Remove Beeper");
	private JButton finchButton = new JButton("Add Finch");
	private JButton wallButton = new JButton("Add/Remove Wall");
	private JButton saveButton = new JButton("Save");
	private JButton saveAsButton = new JButton("Save as");
	private JButton newButton = new JButton("New Terrain");
	private SimulatorEngineWindow sim = null;
	private	JSplitPane	splitPaneH;
	private TerrainImage terrainImage = null;
	private Terrain	map = null;
	private int adding = 99999;
	private int scale = 50;
	private boolean isDirty = false;
	
	
	public TerrainEditorWindow(){
		this.setLayout(new BorderLayout());
	
		rightPanel.setLayout(new GridLayout(7,1));
		Dimension preferredSize = new Dimension(600, (int) super.getSize().getHeight());
		rightPanel.setPreferredSize(preferredSize);
		rightPanel.add(beeperButton);
		rightPanel.add(removeBeeperButton);
		rightPanel.add(finchButton);
		rightPanel.add(wallButton);
		rightPanel.add(saveButton);
		rightPanel.add(saveAsButton);
		rightPanel.add(newButton);
		
		splitPaneH = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT );
		splitPaneH.setLeftComponent(rightPanel);
		splitPaneH.setRightComponent(centerPanel);
		this.add(rightPanel);
		
		beeperButton.addActionListener(this);
		removeBeeperButton.addActionListener(this);
		finchButton.addActionListener(this);
		wallButton.addActionListener(this);
		saveButton.addActionListener(this);
		saveAsButton.addActionListener(this);
		newButton.addActionListener(this);
		clearButtons();
	}

public void newTerrain(){
	//@Description    Creates a new, empty, terrain for the user to edit.
	if (isDirty==false){
		String currentterrainname = "";
		while (currentterrainname.equals("")){
			currentterrainname = JOptionPane.showInputDialog(null, "Enter New Terrain Name: ", "FlowGram", 1);
			if (currentterrainname == null){
				currentterrainname = "";
			}
		}
		String workspace = Application.getInstance().getCurrentProjectPath();
		File file = new File(workspace + File.separator + "Terrains" + File.separator + currentterrainname + ".terr");
	//	System.out.println(workspace + File.separator + "Terrains" + File.separator + currentterrainname + ".terriiii");
		while (file.exists()==true){
			currentterrainname = "";
			while(currentterrainname.equals("")){
				currentterrainname = JOptionPane.showInputDialog(null, "Name already exists please enter a different name: ", "FlowGram", 1);
				file = new File(workspace + File.separator + "Terrains" + File.separator + currentterrainname + ".terr");
			}
			//System.out.println(workspace + File.separator + "Terrains" + File.separator + currentterrainname + ".terr222");
			
		}
		String wholename = workspace + File.separator + "Terrains" + File.separator + currentterrainname + ".terr";
		int xaxis = 99;
		int yaxis = 99;
		String input = "";
		String mess = "EnterTerrain width from 2 to 20:";
		Pattern p = Pattern.compile("[A-Z,a-z,&%$#@!()*^]");
		Matcher m = null;
		while ( xaxis > 20){
			while(input.equalsIgnoreCase("")){	
				input = (JOptionPane.showInputDialog(null, mess, "FlowGram", 1));
			}
			//System.out.println("error");
			m = p.matcher(input);
			if (m.find()){
				//input = (JOptionPane.showInputDialog(null, "Enter Valid Numbers from 2 to 20 : ", "FlowGram", 1));
				mess = "ERROR: Enter Valid Numbers from 2 to 20";
				input ="";
			} else { xaxis = Integer.parseInt(input);
			if (xaxis < 2 || xaxis > 20) {xaxis = 99;}			
				}
		}
		input = "";
		mess = "EnterTerrain highth from 2 to 20:";
		while ( yaxis > 20){
			while(input.equals("")){
				input = (JOptionPane.showInputDialog(null, mess, "FlowGram", 1));
			}
			m = p.matcher(input);
			if (m.find()){
				mess = "ERROR: Enter Valid Numbers from 2 to 20";
				input ="";
			} else { yaxis = Integer.parseInt(input);
				if (yaxis < 2 || yaxis > 20) {yaxis = 99;}			}
		}
		//setup a new terrain with name and size provided by the user
		//and a finch in tile 0,0 pointing south
		String newTerrain = "size " + xaxis + " " + yaxis + "\n" + "finch 0 0 1"; 
		saveNewTerrain(wholename, newTerrain);
		sim.populateTerrainscombo();
		sim.setCombobox(currentterrainname);
		sim.getTerrainImage().update(sim.getTerrainImage().getGraphics());
		this.isDirty = true;
	} else {
		JOptionPane.showMessageDialog(null, "The current terrain has not been saved.\nSave current Terrain before you start new one");
	}
		
}
private void saveNewTerrain(String wholepath, String terrain){
		//@Description  Saves the current terrain to the Terrains Folder under a specific Project;
		//@Description	Terrains are related to projects

		FileWriter fstream = null;
		try {
			fstream = new FileWriter(wholepath);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		BufferedWriter out = new BufferedWriter(fstream);
		try {
			out.write(terrain);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			out.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		this.isDirty = false;
}
public void SaveTerrain(){
	//@Description  Rewrites current terrain current terrain to the Terrains Folder under a specific Project;
	//@Description	Default terrains cannot be rewritten but they can be saved with a different name in the project foler;
	String currentterrainname = sim.getCurrentTerrainName();
	if (currentterrainname.startsWith("defterr")){
		String str = JOptionPane.showInputDialog(null, "You are trying to save a default terrain please enter new name: ", "FlowGram", 1);
		currentterrainname = str;
		if (checkFile(currentterrainname) == true){
			sim.settext("Saving " + sim.getCurrentTerrainName() + " with new name " + currentterrainname);
			saveFile(currentterrainname);
		}
	} else {
		saveFile(currentterrainname);
	}
	
}

private boolean checkFile(String currentterrainname) {
		//@descritption: if the file exist ask the user if he/she want to overwrite and returns the answer in boolean
		String workspace = Application.getInstance().getCurrentProjectPath();
		File currentprojectfolder = new File(workspace + File.separator + "Terrains");
		if (currentprojectfolder.exists() == false) {
			currentprojectfolder.mkdir();
			}
		workspace = workspace + File.separator + "Terrains";
		File file = new File(workspace + File.separator + currentterrainname + ".terr");
		boolean exists = file.exists();
		   if (exists == true) {
			   
			   int n = JOptionPane.showConfirmDialog(null, "File " +  currentterrainname + " already exists do you want to OverWrite?", "FlowGram", JOptionPane.YES_NO_OPTION);
			   if (n == 0){
				   sim.settext(currentterrainname + " was overwritten");
				   return true;
			   } else {
				   sim.settext(currentterrainname + " was not saved if application closes you will loose all the terrain changes");
				   return false;
			   }

		   } else {
			   return true;
			   }
		   
}


private void saveFile(String currentterrainname) {
	//@Description  Saves the current terrain to the Terrains Folder under a specific Project;
	String workspace = Application.getInstance().getCurrentProjectPath();
	File currentprojectfolder = new File(workspace + File.separator + "Terrains");
	if (currentprojectfolder.exists() == false) {
		currentprojectfolder.mkdir();
		}
	workspace = workspace + File.separator + "Terrains";
	sim.settext(workspace);
	String stringtosave = sim.getTerrain().getstringtosave();
	//System.out.println(stringtosave);
	String wholepath = workspace + File.separator + currentterrainname + ".terr"; 
	//File f = new File(wholepath);
	
	FileWriter fstream = null;
	try {
		fstream = new FileWriter(wholepath);
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	BufferedWriter out = new BufferedWriter(fstream);
	try {
		out.write(stringtosave);
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	  try {
		out.close();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	  this.isDirty = false;
}


public void SaveTerrainAs(){
	String str = "";
	while (str.equals("")){
		str = JOptionPane.showInputDialog(null, "Enter new Name: ", "FlowGram", 1);
	}
	String currentterrainname = str;
	if (checkFile(currentterrainname) == true){
		sim.settext("Saving " + sim.getCurrentTerrainName() + " with new name " + currentterrainname);
		saveFile(currentterrainname);
	}
	
}

public void setTerrainImage(TerrainImage terrainImage2) {
	// TODO Auto-generated method stub
	this.terrainImage = terrainImage2;
	
}


public void setTerrain(Terrain terrain) {
	// TODO Auto-generated method stub
	this.map = terrain;
	
}


public void setSimWindow(SimulatorEngineWindow simulatorWindow) {
	// TODO Auto-generated method stub
	this.sim = simulatorWindow;
}


@Override
public void itemStateChanged(ItemEvent arg0) {
	// TODO Auto-generated method stub
	
}


@Override
public void actionPerformed(ActionEvent arg0) {
	// TODO Auto-generated method stub
	
	
	
	Border thickborder = new LineBorder(Color.red, 12);
	String ap = arg0.getActionCommand();
	//System.out.println(ap);
	if (ap.equals("Add Beeper")){
		sim.settext("Adding Beeper Mode Activated. TIP: Click in a tile to add beeper");
		adding = TerrainEditorWindow.ADDBEEPER;
		clearButtons();
		beeperButton.setBorder(thickborder);
		beeperButton.setFocusPainted(true);
	} else if (ap.equals("Remove Beeper")){
		sim.settext("Removing Beeper Activate. TIP: Click over an existing beeper to remove one at the time");
		adding = TerrainEditorWindow.REMOVEBEEPER;
		clearButtons();
		removeBeeperButton.setBorder(thickborder);
			
	} else if (ap.equals("Add Finch")){
		sim.settext("Adding Finch. TIP: If a finch already exist in the terrain it will be moved");
		sim.settext("TIP: If a finch already exist in the tile clicked Orientation will change");
		adding = TerrainEditorWindow.ADDFINCH;
		clearButtons();
		finchButton.setBorder(thickborder);
		
	} else if (ap.equals("Add/Remove Wall")){
		sim.settext("Adding Wall. TIP: click over line to add a Wall click in a Wall to remove it");
		adding = TerrainEditorWindow.ADDWALL;
		clearButtons();
		wallButton.setBorder(thickborder);
		
	} else if (ap.equals("Save")){
		sim.settext("Saving Terrain : " + sim.getCurrentTerrainName());
		SaveTerrain();
		clearButtons();
		saveButton.setBorder(thickborder);
		
	} else if (ap.equals("Save as")){
		
		clearButtons();
		saveAsButton.setBorder(thickborder);
		SaveTerrainAs();
	} else if (ap.equals("New Terrain")){
		sim.settext("Creating New Terrain");
		clearButtons();
		newButton.setBorder(thickborder);
		newTerrain();
	}

}



private void clearButtons() {
	//@Description: sets a thin border to all the buttons
	Border thin = new LineBorder(Color.lightGray, 1);
    
    
	beeperButton.setBorder(thin);
	removeBeeperButton.setBorder(thin);
	finchButton.setBorder(thin);
	wallButton.setBorder(thin);
	saveButton.setBorder(thin);
	saveAsButton.setBorder(thin);
	newButton.setBorder(thin);
	
}

public void mouse(Point p) {
	// TODO Auto-generated method stub
	//System.out.println("Point X: " + p.getX() + " Y: " + p.getY());
	int terrainxpixels = sim.getTerrain().getSizeX()*sim.getTerrainImage().getScale();
	int terrainypixels = sim.getTerrain().getSizeY()*sim.getTerrainImage().getScale();
	if (p.getX()>=0 && p.getX()<terrainxpixels && p.getY()>=0 && p.getY()<terrainypixels){
		if (adding == 99999){
			sim.settext("Select \'Add Beeper\', \'Remove Beeper\', \'Add Wall\' or \'Add Finch\' to proceed");
		} else if (adding == TerrainEditorWindow.ADDBEEPER) {
			this.isDirty = true;
			sim.settext("Adding Beeper");
			addBeeper(p);
		} else if (adding == TerrainEditorWindow.REMOVEBEEPER){
			this.isDirty = true;
			sim.settext("Removing Beeper");
			removeBeeper(p);
		} else if (adding == TerrainEditorWindow.ADDFINCH){
			this.isDirty = true;
			sim.settext("Adding/Moving/Rotating Finch");
			addFinch(p);
		} else if (adding == TerrainEditorWindow.ADDWALL){
			this.isDirty = true;
			sim.settext("Adding/Removing Wall ");
			addWall(p);
		}
	} else {
		sim.settext("ERROR: you clicked outside the terrain");
	}
}
private void addWall(Point p) {
	//@Description: after a point is selected in the map
	int scale = sim.getTerrainImage().getScale();
	sim.getTerrain().addWall(p, scale);
	sim.getTerrainImage().update(sim.getTerrainImage().getGraphics());
}


private void addFinch(Point p) {
	// TODO Auto-generated method stub
	Point p1 = getActualPoint(p);
	sim.getTerrain().addFinch(p1);
	sim.getTerrainImage().update(sim.getTerrainImage().getGraphics());
	sim.settext("Finch was added or turned to tile (" + p1.x+ "," + p1.y + ")" );
}


private Point getActualPoint(Point p2){
	Point p = new Point();
	this.scale = sim.getTerrainImage().getScale();
	int x = (int) p2.getX()/scale;
	int y = (int) p2.getY()/scale;
	p.x = x;
	p.y = y;
	//System.out.println("Tile (" + scale + " "+ p.x + "," + p.y + ")");
	return p;
}
private void removeBeeper(Point p) {
	// TODO Auto-generated method stub
	Point p1 = getActualPoint(p);
	if (sim.getTerrain().removeBeeper(p1) == true){
		sim.getTerrainImage().update(sim.getTerrainImage().getGraphics());
		sim.settext("A Beeper was successfully removed from tile (" + p1.x+ "," + p1.y + ")" );
		
	} else {
		sim.settext("There is no Beeper in tile (" + p1.x+ "," + p1.y + ")" );
	}
	
}


private void addBeeper(Point p) {
	// TODO Auto-generated method stub
	Point p1 = getActualPoint(p);
	Color c = getColor();
	Beeper b = new Beeper(p1.x, p1.y, c);
	sim.getTerrain().addbeeper(b);
	sim.getTerrainImage().update(sim.getTerrainImage().getGraphics());
	sim.settext("Beeper added in tile (" + p1.x + "," + p1.y + ")" );
	}


private Color getColor() {
	// TODO Auto-generated method stub
	Color initialColor = new Color(0,0,0);
	Color newColor = JColorChooser.showDialog(null, "Select Color" , initialColor);
	return newColor;
}


}
